//
// ftManager.cpp
//
#include "stdafx.h"
#include "ftManager.h"

#include "ftNode.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
ftManager::ftManager(void)
	:m_pRootNode(0),
	m_bTraversing(FALSE)
{
	//int n = sizeof(ftNode);
	//ftNode aaa;
	//int b= sizeof(aaa);
	//n= sizeof(ftManager);
}

ftManager::~ftManager(void)
{
	CleanTree();
}


void ftManager::CleanTree()
{
	if (NULL == m_pRootNode)
	{
		return;
	}	
	delete m_pRootNode;
	m_pRootNode = NULL;
}

BOOL ftManager::IsTraversing()
{
	return m_bTraversing;
}

BOOL ftManager::CreateTree(CString csFilePath, lpcbFTManagerStatus pCallbackFun, LPVOID lParam)
{
	ASSERT(!csFilePath.IsEmpty());
	CleanTree();
	ASSERT(NULL == m_pRootNode);
	m_bTraversing = TRUE;

	//create root node
	m_pRootNode = new ftNode;
	CString csRootPath = RemoveBackSlash(csFilePath);
// 	csRootPath += _T("\\*");
	m_pRootNode->m_csName = csRootPath;

	//node queue
	CArray<ftNode*, ftNode*> arrNode;
	arrNode.Add(m_pRootNode);

	//
	int nSizeArr = arrNode.GetSize();
	while (nSizeArr > 0)
	{
		ftNode* pCurNode = arrNode.GetAt(0);
		ASSERT(NULL != pCurNode);	
		CString csCurPath = GetFullPath(pCurNode);
		csCurPath += _T("\\*");
		csCurPath = _T("\\\\?\\") + csCurPath;
		//
		WIN32_FIND_DATA FindFileData;
		memset(&FindFileData, 0, sizeof(WIN32_FIND_DATA));
		HANDLE hFind;
		hFind = FindFirstFile(csCurPath, &FindFileData);
		if (INVALID_HANDLE_VALUE == hFind)
		{
			int nSize = pCurNode->m_pParent->m_arrSubNode.GetSize();
			int i;
			for(i=0; i<nSize; i++)
			{
				if (pCurNode == pCurNode->m_pParent->m_arrSubNode.GetAt(i))
				{
					pCurNode->m_pParent->m_arrSubNode.RemoveAt(i);
					break;
				}
			}	
			delete pCurNode;
			arrNode.RemoveAt(0);
			nSizeArr = arrNode.GetSize();
			continue;
// 			return FALSE;
		}
	
		LARGE_INTEGER llCurSize = {0,0};
		LARGE_INTEGER llLeafSize = {0,0};
		ftNode* pChildNode = NULL;
		BOOL bRes = TRUE;
		do
		{
			pChildNode = new ftNode;
			ASSERT(NULL != pChildNode);
//			memcpy(&(pChildNode->m_fd), &FindFileData, sizeof(WIN32_FIND_DATA));
			//dir or file
			if (FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
			{
				if (IsDot(FindFileData.cFileName))
				{
					pCurNode->m_dwFileAttributes = FindFileData.dwFileAttributes;
					//pCurNode->m_ftLastWriteTime = FindFileData.ftLastWriteTime;
					delete pChildNode;
					pChildNode = NULL;
				}
				else
				{
					pChildNode->m_csName = FindFileData.cFileName;
					pChildNode->m_dwFileAttributes = FindFileData.dwFileAttributes;
				//	pChildNode->ftLastWriteTime = FindFileData.ftLastWriteTime;
					pChildNode->m_pParent = pCurNode;
					pCurNode->m_arrSubNode.Add(pChildNode);	
					//add to queue
					arrNode.Add(pChildNode);
				}
			}
			else
			{
				pChildNode->m_csName = FindFileData.cFileName;
				pChildNode->m_dwFileAttributes = FindFileData.dwFileAttributes;
				//pChildNode->ftLastWriteTime = FindFileData.ftLastWriteTime;
				pChildNode->m_dwNodeSizeHigh = FindFileData.nFileSizeHigh;
				pChildNode->m_dwNodeSizeLow = FindFileData.nFileSizeLow;
				llLeafSize.HighPart = pChildNode->m_dwNodeSizeHigh;
				llLeafSize.LowPart = pChildNode->m_dwNodeSizeLow;
				llCurSize.QuadPart += llLeafSize.QuadPart;
				pChildNode->m_pParent = pCurNode;
				pCurNode->m_arrLeaf.Add(pChildNode);
			}
			bRes = FindNextFile(hFind, &FindFileData);
		}
		while (bRes);	
		if (ERROR_NO_MORE_FILES != GetLastError())
		{
		}
		if (!FindClose(hFind))
		{
			continue;
// 			return FALSE;
		}

		//Set Current Node Size
		if (llCurSize.QuadPart>0)
		{
			LARGE_INTEGER llParentSize = {0,0};
			pCurNode->m_dwNodeSizeHigh = llCurSize.HighPart;
			pCurNode->m_dwNodeSizeLow = llCurSize.LowPart;
			ftNode* m_pParent = pCurNode->m_pParent;
			while (NULL != m_pParent)
			{
				llParentSize.HighPart = m_pParent->m_dwNodeSizeHigh;
				llParentSize.LowPart = m_pParent->m_dwNodeSizeLow;
				llParentSize.QuadPart += llCurSize.QuadPart;
				m_pParent->m_dwNodeSizeHigh = llParentSize.HighPart;
				m_pParent->m_dwNodeSizeLow = llParentSize.LowPart;
				m_pParent = m_pParent->m_pParent;
			}
		}
		//if have subNode then sublevel+1
		if (pCurNode->m_arrSubNode.GetSize()>0)
		{
			pCurNode->m_nSubLevel += 1;
			int nLevel = pCurNode->m_nSubLevel + 1;
			ftNode* m_pParent = pCurNode->m_pParent;
			while(NULL != m_pParent)
			{
				if (m_pParent->m_nSubLevel < nLevel)
				{
					m_pParent->m_nSubLevel = nLevel;
					nLevel++;
				}
				else
				{
					break;
				}
				m_pParent = m_pParent->m_pParent;
			}
		}
		arrNode.RemoveAt(0);
		nSizeArr = arrNode.GetSize();
		if (pCallbackFun)
		{
			ASSERT(NULL != lParam);
			pCallbackFun(m_pRootNode->m_dwNodeSizeHigh, m_pRootNode->m_dwNodeSizeLow, (DWORD)pCurNode, lParam);
		}
	}
	m_bTraversing = FALSE;

	return TRUE;
}

CString ftManager::RemoveBackSlash(CString& csPath)
{
	CString csRet(csPath);
	int nSize = csRet.GetLength();
	while((csRet.GetAt(nSize-1) == '\\')||(csRet.GetAt(nSize-1) == '*'))
	{
		csRet = csRet.Left(nSize-1);
		nSize = csRet.GetLength();
	}
	return csRet;
}

CString ftManager::GetFullPath(ftNode* pNode)
{
	ASSERT(NULL != pNode);
	CString csPath = pNode->m_csName;
	ftNode* m_pParent = pNode->m_pParent;
	while (m_pParent)
	{
		csPath = m_pParent->m_csName + _T("\\") + csPath;
		m_pParent = m_pParent->m_pParent;
	}
	return csPath;
}

BOOL ftManager::IsDot(CString csPath)
{
	if (csPath == _T(".") || csPath == _T(".."))
	{
		return TRUE;
	}
	return FALSE;
}

UINT ftManager::GetTreeLevel()
{
	ASSERT(NULL != m_pRootNode);
	return m_pRootNode->m_nSubLevel;
}

void ftManager::GetTreeSize(LARGE_INTEGER& llSize)
{
	ASSERT(NULL != m_pRootNode);
	llSize.HighPart = m_pRootNode->m_dwNodeSizeHigh;
	llSize.LowPart = m_pRootNode->m_dwNodeSizeLow;
}

void ftManager::CountChild(ftNode* pRootNode)
{
	
}
